#include "statsxx/machine_learning/NeuralNet.hpp"

// STL
#include <iostream>

// BOOST
#include <boost/range/adaptor/reversed.hpp>

// jSCIENCE
#include "jutility.hpp"


//
// DESC: Passes input through the network, storing the final results in output.
//
// NOTES:
//     ! IMPORTANT: the input and output ordering MUST be preserved during any and all use of the network (successive calls, individual time frames, etc.)
//     ! IMPORTANT: input MUST be stored temporally in the order t, t-1, ..., t-(n-1), t-n
//
inline void NEURAL_NET::evaluate(const std::vector<std::vector<double>> &input, std::vector<double> &output)
{
    // << JMM >> maybe check consistency?

    this->clear_memory();

    // PRESENT INPUT IN THE ORDER t-n, t-(n-1), ..., t-1, t -- SUCCESSIVE CALLS BUILD UP MORE AND MORE MEMORY
    for( auto inp : boost::adaptors::reverse(input) )
    {
        this->deactivate_network();

        for( auto &n : m_neurons )
        {
            n.m_output.insert(n.m_output.begin(), 0.0);
        }

        /*
        // ****
        std::cout << "here 9991" << std::endl;
        for( auto &n : m_neurons )
        {
            std::cout << "ID: " << n.m_ID << std::endl;

            for( auto o : n.m_output )
            {
                std::cout << "o: " << o << std::endl;
            }
        }
        // *****
        */

        this->forward_prop(inp);

        /*
        // ****
        std::cout << "here 9992" << std::endl;
        for( auto &n : m_neurons )
        {
            std::cout << "ID: " << n.m_ID << std::endl;

            for( auto o : n.m_output )
            {
                std::cout << "o: " << o << std::endl;
            }
        }
        // *****
        */

    }

    this->assign_output(output);
}
